/*
 * Copyright (c) 2013 WDCY Information Technology Co. Ltd
 * www.wdcy.cc
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * WDCY Information Technology Co. Ltd ("Confidential Information").
 * You shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement you
 * entered into with WDCY Information Technology Co. Ltd.
 */
package com.monkey.web.platform.service.impl;

import com.monkey.core.domain.auth.UserResourcePermission;
import com.monkey.core.domain.auth.UserResourcePermissionRepository;
import com.monkey.core.domain.permission.Permission;
import com.monkey.core.domain.permission.PermissionRepository;
import com.monkey.core.domain.resource.Menu;
import com.monkey.core.domain.resource.MenuRepository;
import com.monkey.core.domain.role.RoleResourcePermission;
import com.monkey.core.domain.user.User;
import com.monkey.core.domain.user.UserRepository;
import com.monkey.core.exception.MonkeyException;
import com.monkey.core.plugin.dto.MonkeyDto;
import com.monkey.core.repository.search.SearchOperator;
import com.monkey.core.repository.search.Searchable;
import com.monkey.core.service.BaseServiceImpl;
import com.monkey.core.web.response.MonkeyResponseDto;
import com.monkey.utils.MonkeyUtils;
import com.monkey.web.dto.request.permission.GrantPermissionRequestDto;
import com.monkey.web.platform.exception.CanNotFoundPermissionException;
import com.monkey.web.platform.exception.CanNotFoundResourceException;
import com.monkey.web.platform.service.MenuService;
import com.monkey.web.platform.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author Wu Tianqiang
 */
@Service
public class PermissionServiceImpl extends BaseServiceImpl<Permission, Long> implements PermissionService {

    @Autowired
    private MenuService menuService;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private UserResourcePermissionRepository userResourcePermissionRepository;
    @Autowired
    private MenuRepository menuRepository;
    @Autowired
    private PermissionRepository permissionRepository;

    @Override
    public void addPermission(MonkeyDto monkeyDto) {
        Permission permission = Permission.createFromMonkeyDto(monkeyDto);

        Searchable searchable1 = Searchable.newSearchable();
        searchable1.addSearchFilter("name", SearchOperator.eq, permission.getName());
        if (exist(searchable1)) {
            throw new MonkeyException("权限名称已经存在");
        }

        Searchable searchable2 = Searchable.newSearchable();
        searchable2.addSearchFilter("permission", SearchOperator.eq, permission.getPermission());
        if (exist(searchable2)) {
            throw new MonkeyException("权限标识符已经存在");
        }
        save(permission);
    }

    @Override
    public void modifyPermission(MonkeyDto monkeyDto) {
        Permission permission = findOne(monkeyDto.getLong("id"));
        Permission.modifyFromMonkeyDto(permission, monkeyDto);

        Searchable searchable1 = Searchable.newSearchable();
        searchable1.addSearchFilter("id", SearchOperator.ne, permission.getId());
        searchable1.addSearchFilter("name", SearchOperator.eq, permission.getName());
        if (exist(searchable1)) {
            throw new MonkeyException("权限名称已经存在");
        }

        Searchable searchable2 = Searchable.newSearchable();
        searchable2.addSearchFilter("id", SearchOperator.ne, permission.getId());
        searchable2.addSearchFilter("permission", SearchOperator.eq, permission.getPermission());
        if (exist(searchable2)) {
            throw new MonkeyException("权限标识符已经存在");
        }
        update(permission);
    }

    @Override
    public MonkeyResponseDto grantPermissionToUser(GrantPermissionRequestDto grantPermissionRequestDto) {
        User user = userRepository.findOne(grantPermissionRequestDto.getUserId());
        Map<Long, String> authorizations = grantPermissionRequestDto.getAuthorizations();
        if (MonkeyUtils.isEmpty(authorizations)) {
            return new MonkeyResponseDto().fail("grant.authorizations.not.null");
        }
        List<UserResourcePermission> userResourcePermissions = loadUserResourcePermissions(user, authorizations);
        userResourcePermissionRepository.save(userResourcePermissions);
        return new MonkeyResponseDto().success("grant.permission.to.user.success");
    }

    private List<UserResourcePermission> loadUserResourcePermissions(User user, Map<Long, String> authorizations) {
        List<UserResourcePermission> userResourcePermissions = new ArrayList<>();
        Set<Long> keys = authorizations.keySet();
        for (Long key : keys) {
            String[] permissionIds = authorizations.get(key).split(RoleResourcePermission.DEFAULT_PERMISSIONS_SEPARATOR);
            for (String permissionId : permissionIds) {
                UserResourcePermission userResourcePermission = new UserResourcePermission();
                userResourcePermission.setUser(user);

                Menu menu = menuRepository.findOne(key);
                if (MonkeyUtils.isEmpty(menu)) {
                    throw new CanNotFoundResourceException(new Object[]{key});
                }
                userResourcePermission.setMenu(menu);

                Permission permission = permissionRepository.findOne(Long.valueOf(permissionId));
                if (MonkeyUtils.isEmpty(permission)) {
                    throw new CanNotFoundPermissionException();
                }
                userResourcePermission.setPermission(permission);

                userResourcePermissions.add(userResourcePermission);
            }
        }
        return userResourcePermissions;
    }

    @Override
    public Set<String> findStringPermissions(Long userId) {
        Set<String> permissions = new HashSet<>();
        List<UserResourcePermission> userResourcePermissions = userResourcePermissionRepository.findByUserId(userId);
        for (UserResourcePermission userResourcePermission : userResourcePermissions) {
            Menu menu = userResourcePermission.getMenu();
            Permission permission = userResourcePermission.getPermission();
            String actualResourceIdentity = menuService.findActualMenuIdentity(menu);
            permissions.add(actualResourceIdentity + Permission.PART_DIVIDER_TOKEN + permission.getPermission());
        }
        return permissions;
    }


}